<template>
  <div class="volcano-container">
    <a class="tools" @click="togglePlay" :title="playing ? '暂停环绕' : '环绕飞行'">
      <PlayCircleOutlined v-if="!playing" />
      <PauseCircleOutlined v-if="playing" />
    </a>
    <div id="volcano-container" />
  </div>
</template>

<script>
import { PlayCircleOutlined, PauseCircleOutlined, PlayCircleFilled, PauseCircleFilled } from '@ant-design/icons-vue';
import * as psLib from '@lib/ParticleSystem';
import * as volcano from './lib/volcano';
import * as $Cesium from '@cesium/Source/Cesium.js';

let Cesium = $Cesium

// Cesium.Camera.DEFAULT_VIEW_FACTOR=0.25//摄像机视口远近参数，可设置地球大小

import { defineComponent, ref, onMounted, h } from 'vue';
export default defineComponent({
  name: 'volcano',
  components: { PlayCircleOutlined, PauseCircleOutlined, PlayCircleFilled, PauseCircleFilled },
  setup() {
    return {
      viewer: null
    };
  },
  data() {
    return {
      playing: false
    };
  },
  mounted() {
    this.init();
  },
  methods: {
    init() {
      // Grant CesiumJS access to your ion assets
      Cesium.Ion.defaultAccessToken = $accessToken.default;

      var viewer = new Cesium.Viewer('volcano-container', {
        selectionIndicator: false,
        animation: false,
        // baseLayerPicker: false,
        geocoder: false,
        timeline: false,
        navigationHelpButton: false,
        homeButton: false,
        sceneModePicker: false,
        fullscreenButton: false, //视察全屏按钮
        infoBox: false,
        shouldAnimate: true,
        terrainProvider: Cesium.createWorldTerrain()
      });

      viewer.extend(Cesium.viewerCesiumInspectorMixin)

      this.viewer = viewer;

      var handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
      handler.setInputAction((movement)=>{
        // console.log(viewer)
        // console.log(movement)
      }, Cesium.ScreenSpaceEventType.WHEEL);

      // Lock camera to a point
      // var center = Cesium.Cartesian3.fromRadians(2.4213211833389243, 0.6171926869414084, 3626.0426275055174);
      var center = Cesium.Cartesian3.fromDegrees(138.73148465094258, 35.36253610808178, 3626.042627504157);
      // this.doEmit(center);
      // this.doFirework(center);
      // this.emit(center);

      var transform = Cesium.Transforms.eastNorthUpToFixedFrame(center);
      viewer.scene.camera.lookAtTransform(transform, new Cesium.HeadingPitchRange(0, -Math.PI / 20, 10000));

      var ellipsoid = viewer.scene.globe.ellipsoid;
      var cartographic = ellipsoid.cartesianToCartographic(center);
      var lat = Cesium.Math.toDegrees(cartographic.latitude);
      var lng = Cesium.Math.toDegrees(cartographic.longitude);
      var alt = cartographic.height;

      // console.log(lng, lat, alt);

      volcano.volcano_burst(Cesium,viewer,center)

      const { playing, start } = this;

      playing && start();
    },
    rotate(clock) {
      this.viewer.scene.camera.rotateRight(0.005);
    },
    start() {
      let { viewer, rotate } = this;
      viewer.clock.onTick.addEventListener(rotate);
    },
    stop() {
      let { viewer, rotate } = this;
      viewer.clock.onTick.removeEventListener(rotate);
    },
    togglePlay() {
      this.playing = !this.playing;
      let { playing, start, stop } = this;
      if (playing) {
        start();
      } else {
        stop();
      }
    },
    doEmit(center){
      let { viewer } = this;
      let { scene } = viewer;
      // Cesium.Math.setRandomNumberSeed(3);
      function startup() {
        //Sandcastle_Begin
        // var viewer = new Cesium.Viewer("cesiumContainer");
        //Set the random number seed for consistent results.
        Cesium.Math.setRandomNumberSeed(3);

        //Set bounds of our simulation time
        var start = Cesium.JulianDate.fromDate(new Date(2015, 2, 25, 16));
        var stop = Cesium.JulianDate.addSeconds(
          start,
          120,
          new Cesium.JulianDate()
        );

        //Make sure viewer is at the desired time.
        viewer.clock.startTime = start.clone();
        viewer.clock.stopTime = stop.clone();
        viewer.clock.currentTime = start.clone();
        viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP; //Loop at the end
        viewer.clock.multiplier = 1;
        viewer.clock.shouldAnimate = true;

        //Set timeline to simulation bounds
        // viewer.timeline.zoomTo(start, stop);

        var viewModel = {
          emissionRate: 5.0,
          gravity: 0.0,
          minimumParticleLife: 1.2,
          maximumParticleLife: 1.2,
          minimumSpeed: 1.0,
          maximumSpeed: 4.0,
          startScale: 1.0,
          endScale: 5.0,
          particleSize: 25.0,
        };

        // Cesium.knockout.track(viewModel);
        // var toolbar = document.getElementById("toolbar");
        // Cesium.knockout.applyBindings(viewModel, toolbar);

        var entityPosition = new Cesium.Cartesian3();
        var entityOrientation = new Cesium.Quaternion();
        var rotationMatrix = new Cesium.Matrix3();
        var modelMatrix = new Cesium.Matrix4();

        function computeModelMatrix(entity, time) {
          return entity.computeModelMatrix(time, new Cesium.Matrix4());
        }

        var emitterModelMatrix = new Cesium.Matrix4();
        var translation = new Cesium.Cartesian3();
        var rotation = new Cesium.Quaternion();
        var hpr = new Cesium.HeadingPitchRoll();
        var trs = new Cesium.TranslationRotationScale();

        function computeEmitterModelMatrix() {
          hpr = Cesium.HeadingPitchRoll.fromDegrees(0.0, 0.0, 0.0, hpr);
          trs.translation = Cesium.Cartesian3.fromElements(
            -4.0,
            0.0,
            1.4,
            translation
          );
          trs.rotation = Cesium.Quaternion.fromHeadingPitchRoll(hpr, rotation);

          return Cesium.Matrix4.fromTranslationRotationScale(
            trs,
            emitterModelMatrix
          );
        }

        var pos1 = Cesium.Cartesian3.fromDegrees(
          -75.15787310614596,
          39.97862668312678
        );
        var pos2 = Cesium.Cartesian3.fromDegrees(
          -75.1633691390455,
          39.95355089912078
        );
        var position = new Cesium.SampledPositionProperty();

        position.addSample(start, pos1);
        position.addSample(stop, pos2);

        var entity = viewer.entities.add({
          availability: new Cesium.TimeIntervalCollection([
            new Cesium.TimeInterval({
              start: start,
              stop: stop,
            }),
          ]),
          model: {
            uri: "../../SampleData/models/CesiumMilkTruck/CesiumMilkTruck.glb",
            minimumPixelSize: 64,
          },
          viewFrom: new Cesium.Cartesian3(-100.0, 0.0, 100.0),
          position: position,
          orientation: new Cesium.VelocityOrientationProperty(position),
        });
        viewer.trackedEntity = entity;

        var scene = viewer.scene;
        var particleSystem = scene.primitives.add(
          new Cesium.ParticleSystem({
            image: require('@lib/data/smoke.png'),

            startColor: Cesium.Color.LIGHTSEAGREEN.withAlpha(0.7),
            endColor: Cesium.Color.WHITE.withAlpha(0.0),

            startScale: viewModel.startScale,
            endScale: viewModel.endScale,

            minimumParticleLife: viewModel.minimumParticleLife,
            maximumParticleLife: viewModel.maximumParticleLife,

            minimumSpeed: viewModel.minimumSpeed,
            maximumSpeed: viewModel.maximumSpeed,

            imageSize: new Cesium.Cartesian2(
              viewModel.particleSize,
              viewModel.particleSize
            ),

            emissionRate: viewModel.emissionRate,

            bursts: [
              // these burst will occasionally sync to create a multicolored effect
              new Cesium.ParticleBurst({
                time: 5.0,
                minimum: 10,
                maximum: 100,
              }),
              new Cesium.ParticleBurst({
                time: 10.0,
                minimum: 50,
                maximum: 100,
              }),
              new Cesium.ParticleBurst({
                time: 15.0,
                minimum: 200,
                maximum: 300,
              }),
            ],

            lifetime: 16.0,

            emitter: new Cesium.CircleEmitter(2.0),

            emitterModelMatrix: computeEmitterModelMatrix(),

            updateCallback: applyGravity,
          })
        );

        var gravityScratch = new Cesium.Cartesian3();

        function applyGravity(p, dt) {
          // We need to compute a local up vector for each particle in geocentric space.
          var position = p.position;

          Cesium.Cartesian3.normalize(position, gravityScratch);
          Cesium.Cartesian3.multiplyByScalar(
            gravityScratch,
            viewModel.gravity * dt,
            gravityScratch
          );

          p.velocity = Cesium.Cartesian3.add(
            p.velocity,
            gravityScratch,
            p.velocity
          );
        }

        viewer.scene.preUpdate.addEventListener(function (scene, time) {
          particleSystem.modelMatrix = computeModelMatrix(entity, time);

          // Account for any changes to the emitter model matrix.
          particleSystem.emitterModelMatrix = computeEmitterModelMatrix();

          // Spin the emitter if enabled.
          if (viewModel.spin) {
            viewModel.heading += 1.0;
            viewModel.pitch += 1.0;
            viewModel.roll += 1.0;
          }
        });

        Cesium.knockout
          .getObservable(viewModel, "emissionRate")
          .subscribe(function (newValue) {
            particleSystem.emissionRate = parseFloat(newValue);
          });

        Cesium.knockout
          .getObservable(viewModel, "particleSize")
          .subscribe(function (newValue) {
            var particleSize = parseFloat(newValue);
            particleSystem.minimumImageSize.x = particleSize;
            particleSystem.minimumImageSize.y = particleSize;
            particleSystem.maximumImageSize.x = particleSize;
            particleSystem.maximumImageSize.y = particleSize;
          });

        Cesium.knockout
          .getObservable(viewModel, "minimumParticleLife")
          .subscribe(function (newValue) {
            particleSystem.minimumParticleLife = parseFloat(newValue);
          });

        Cesium.knockout
          .getObservable(viewModel, "maximumParticleLife")
          .subscribe(function (newValue) {
            particleSystem.maximumParticleLife = parseFloat(newValue);
          });

        Cesium.knockout
          .getObservable(viewModel, "minimumSpeed")
          .subscribe(function (newValue) {
            particleSystem.minimumSpeed = parseFloat(newValue);
          });

        Cesium.knockout
          .getObservable(viewModel, "maximumSpeed")
          .subscribe(function (newValue) {
            particleSystem.maximumSpeed = parseFloat(newValue);
          });

        Cesium.knockout
          .getObservable(viewModel, "startScale")
          .subscribe(function (newValue) {
            particleSystem.startScale = parseFloat(newValue);
          });

        Cesium.knockout
          .getObservable(viewModel, "endScale")
          .subscribe(function (newValue) {
            particleSystem.endScale = parseFloat(newValue);
          });

        var options = [
          {
            text: "Circle Emitter",
            onselect: function () {
              particleSystem.emitter = new Cesium.CircleEmitter(2.0);
            },
          },
          {
            text: "Sphere Emitter",
            onselect: function () {
              particleSystem.emitter = new Cesium.SphereEmitter(2.5);
            },
          },
          {
            text: "Cone Emitter",
            onselect: function () {
              particleSystem.emitter = new Cesium.ConeEmitter(
                Cesium.Math.toRadians(45.0)
              );
            },
          },
          {
            text: "Box Emitter",
            onselect: function () {
              particleSystem.emitter = new Cesium.BoxEmitter(
                new Cesium.Cartesian3(10.0, 10.0, 10.0)
              );
            },
          },
        ];

        Sandcastle.addToolbarMenu(options);
        //Sandcastle_End
        Sandcastle.finishedLoading();
      }
      if (typeof Cesium !== "undefined") {
        window.startupCalled = true;
        startup(Cesium);
      }
    },
    doFirework(center) {
      let { viewer } = this;
      let { scene } = viewer;
      Cesium.Math.setRandomNumberSeed(315);

      var modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(center);
      var emitterInitialLocation = new Cesium.Cartesian3(0.0, 0.0, 100.0);

      var particleCanvas;

      function getImage() {
        if (!Cesium.defined(particleCanvas)) {
          particleCanvas = document.createElement('canvas');
          particleCanvas.width = 20;
          particleCanvas.height = 20;
          var context2D = particleCanvas.getContext('2d');
          context2D.beginPath();
          context2D.arc(8, 8, 8, 0, Cesium.Math.TWO_PI, true);
          context2D.closePath();
          context2D.fillStyle = 'rgb(255, 255, 255)';
          context2D.fill();
        }
        return particleCanvas;
      }

      var minimumExplosionSize = 30.0;
      var maximumExplosionSize = 100.0;
      var particlePixelSize = new Cesium.Cartesian2(7.0, 7.0);
      var burstSize = 400.0;
      var lifetime = 10.0;
      var numberOfFireworks = 20.0;

      var emitterModelMatrixScratch = new Cesium.Matrix4();

      function createFirework(offset, color, bursts) {
        var position = Cesium.Cartesian3.add(emitterInitialLocation, offset, new Cesium.Cartesian3());
        var emitterModelMatrix = Cesium.Matrix4.fromTranslation(position, emitterModelMatrixScratch);
        var particleToWorld = Cesium.Matrix4.multiply(modelMatrix, emitterModelMatrix, new Cesium.Matrix4());
        var worldToParticle = Cesium.Matrix4.inverseTransformation(particleToWorld, particleToWorld);

        var size = Cesium.Math.randomBetween(minimumExplosionSize, maximumExplosionSize);
        var particlePositionScratch = new Cesium.Cartesian3();
        var force = function(particle) {
          var position = Cesium.Matrix4.multiplyByPoint(worldToParticle, particle.position, particlePositionScratch);
          if (Cesium.Cartesian3.magnitudeSquared(position) >= size * size) {
            Cesium.Cartesian3.clone(Cesium.Cartesian3.ZERO, particle.velocity);
          }
        };

        var normalSize = (size - minimumExplosionSize) / (maximumExplosionSize - minimumExplosionSize);
        var minLife = 0.3;
        var maxLife = 1.0;
        var life = normalSize * (maxLife - minLife) + minLife;

        scene.primitives.add(
          new Cesium.ParticleSystem({
            image: getImage(),
            startColor: color,
            endColor: color.withAlpha(0.0),
            particleLife: life,
            speed: 100.0,
            imageSize: particlePixelSize,
            emissionRate: 0,
            emitter: new Cesium.SphereEmitter(0.1),
            bursts: bursts,
            lifetime: lifetime,
            updateCallback: force,
            modelMatrix: modelMatrix,
            emitterModelMatrix: emitterModelMatrix
          })
        );
      }

      var xMin = -100.0;
      var xMax = 100.0;
      var yMin = -80.0;
      var yMax = 100.0;
      var zMin = -50.0;
      var zMax = 500.0;

      var colorOptions = [
        {
          minimumRed: 0.75,
          green: 0.0,
          minimumBlue: 0.8,
          alpha: 1.0
        },
        {
          red: 0.0,
          minimumGreen: 0.75,
          minimumBlue: 0.8,
          alpha: 1.0
        },
        {
          red: 0.0,
          green: 0.0,
          minimumBlue: 0.8,
          alpha: 1.0
        },
        {
          minimumRed: 0.75,
          minimumGreen: 0.75,
          blue: 0.0,
          alpha: 1.0
        }
      ];

      for (var i = 0; i < numberOfFireworks; ++i) {
        var x = Cesium.Math.randomBetween(xMin, xMax);
        var y = Cesium.Math.randomBetween(yMin, yMax);
        var z = Cesium.Math.randomBetween(zMin, zMax);
        var offset = new Cesium.Cartesian3(x, y, z);
        var color = Cesium.Color.fromRandom(colorOptions[i % colorOptions.length]);

        var bursts = [];
        for (var j = 0; j < 3; ++j) {
          bursts.push(
            new Cesium.ParticleBurst({
              time: Cesium.Math.nextRandomNumber() * lifetime,
              minimum: burstSize,
              maximum: burstSize
            })
          );
        }

        createFirework(offset, color, bursts);
      }

      var camera = scene.camera;
      var cameraOffset = new Cesium.Cartesian3(-300.0, 0.0, 0.0);
      camera.lookAtTransform(modelMatrix, cameraOffset);
      camera.lookAtTransform(Cesium.Matrix4.IDENTITY);

      var toFireworks = Cesium.Cartesian3.subtract(emitterInitialLocation, cameraOffset, new Cesium.Cartesian3());
      Cesium.Cartesian3.normalize(toFireworks, toFireworks);
      var angle = Cesium.Math.PI_OVER_TWO - Math.acos(Cesium.Cartesian3.dot(toFireworks, Cesium.Cartesian3.UNIT_Z));
      camera.lookUp(angle);
    },

    emit(center) {
      let { viewer } = this;
      function startup() {
        var planePosition = center;
        var particlesOffset = new Cesium.Cartesian3();
        var cameraLocation = Cesium.Cartesian3.add(planePosition, particlesOffset, new Cesium.Cartesian3());

        // Add plane to scene
        var hpr = new Cesium.HeadingPitchRoll(0.0, Cesium.Math.PI_OVER_TWO, 0.0);
        var orientation = Cesium.Transforms.headingPitchRollQuaternion(planePosition, hpr);
        var entity = viewer.entities.add({
          // model: {
          //   uri: require("../../lib/data/models/CesiumAir/Cesium_Air.glb"),
          //   scale: 3.5,
          // },
          position: planePosition,
          orientation: orientation
        });

        // creating particles model matrix
        var translationOffset = Cesium.Matrix4.fromTranslation(particlesOffset, new Cesium.Matrix4());
        var translationOfPlane = Cesium.Matrix4.fromTranslation(planePosition, new Cesium.Matrix4());
        var particlesModelMatrix = Cesium.Matrix4.multiplyTransformation(translationOfPlane, translationOffset, new Cesium.Matrix4());

        // creating the particle systems
        var rocketOptions = {
          numberOfSystems: 50.0,
          iterationOffset: 0.1,
          cartographicStep: 0.000001,
          baseRadius: 0.0005,

          colorOptions: [
            {
              minimumRed: 1.0,
              green: 0.5,
              minimumBlue: 0.05,
              alpha: 1.0
            },
            {
              red: 0.9,
              minimumGreen: 0.6,
              minimumBlue: 0.01,
              alpha: 1.0
            },
            {
              red: 0.8,
              green: 0.05,
              minimumBlue: 0.09,
              alpha: 1.0
            },
            {
              minimumRed: 1,
              minimumGreen: 0.05,
              blue: 0.09,
              alpha: 1.0
            }
          ]
        };

        var cometOptions = {
          numberOfSystems: 200.0,
          iterationOffset: 0.003,
          cartographicStep: 0.0000001,
          baseRadius: 0.0005,

          colorOptions: [
            {
              red: 0.6,
              green: 0.6,
              blue: 0.6,
              alpha: 1.0
            },
            {
              red: 0.6,
              green: 0.6,
              blue: 0.9,
              alpha: 0.9
            },
            {
              red: 0.5,
              green: 0.5,
              blue: 0.7,
              alpha: 0.5
            }
          ]
        };

        var scratchCartesian3 = new Cesium.Cartesian3();
        var scratchCartographic = new Cesium.Cartographic();

        var forceFunction = function(options, iteration) {
          return function(particle, dt) {
            dt = Cesium.Math.clamp(dt, 0.0, 100);

            scratchCartesian3 = Cesium.Cartesian3.normalize(particle.position, new Cesium.Cartesian3());
            scratchCartesian3 = Cesium.Cartesian3.multiplyByScalar(scratchCartesian3, 40.0 * dt, scratchCartesian3);

            scratchCartesian3 = Cesium.Cartesian3.add(particle.position, scratchCartesian3, scratchCartesian3);
            scratchCartographic = Cesium.Cartographic.fromCartesian(scratchCartesian3, Cesium.Ellipsoid.WGS84, scratchCartographic);

            var angle = (Cesium.Math.PI * 2.0 * iteration) / options.numberOfSystems;
            iteration += options.iterationOffset;
            scratchCartographic.longitude += Math.cos(angle) * options.cartographicStep * 30.0 * dt;
            scratchCartographic.latitude += Math.sin(angle) * options.cartographicStep * 30.0 * dt;

            particle.position = Cesium.Cartographic.toCartesian(scratchCartographic);
          };
        };

        var matrix4Scratch = new Cesium.Matrix4();
        var scratchAngleForOffset = 0.0;
        var scratchOffset = new Cesium.Cartesian3();
        var imageSize = new Cesium.Cartesian2(15.0, 15.0);

        const image = require('@lib/data/smoke.png');
        function getImage(){
          return image
        }

        function createParticleSystems(options, systemsArray) {
          var length = options.numberOfSystems;
          for (var i = 0; i < length; ++i) {
            scratchAngleForOffset = (Math.PI * 2.0 * i) / options.numberOfSystems;
            scratchOffset.x += options.baseRadius * Math.cos(scratchAngleForOffset);
            scratchOffset.y += options.baseRadius * Math.sin(scratchAngleForOffset);

            var emitterModelMatrix = Cesium.Matrix4.fromTranslation(scratchOffset, matrix4Scratch);
            var color = Cesium.Color.fromRandom(options.colorOptions[i % options.colorOptions.length]);
            var force = forceFunction(options, i);

            var item = viewer.scene.primitives.add(
              new Cesium.ParticleSystem({
                image: getImage(),
                startColor: color,
                endColor: color.withAlpha(0.50),
                particleLife: 10,
                speed: 0.00005,
                imageSize: imageSize,
                emissionRate: 1.0,
                emitter: new Cesium.CircleEmitter(1000),
                lifetime: 10,
                updateCallback: force,
                modelMatrix: particlesModelMatrix,
                emitterModelMatrix: emitterModelMatrix
              })
            );
            // systemsArray.push(item);
          }
        }

        var rocketSystems = [];
        var cometSystems = [];
        // createParticleSystems(rocketOptions, rocketSystems);
        createParticleSystems(cometOptions, cometSystems);
      }

      if (typeof Cesium !== 'undefined') {
        window.startupCalled = true;
        startup(Cesium);
      }
    }
  }
});
</script>

<style lang="less">
.volcano-container {
  #volcano-container {
    width: 100%;
    height: 100%;
    .cesium-viewer-bottom {
      display: none !important;
    }
  }

  .tools {
    position: absolute;
    top: 57px;
    left: 7px;
    font-size: 1.5em;
    padding: 4px 14px;
    color: white;
    z-index: 9999;
    background-color: rgba(40, 48, 60, 1);
    border-radius: 5px;
    opacity: 0.6;
    transition: all 500ms;
    &:hover {
      opacity: 0.8;
    }
  }
}
</style>
